<?php

/**
 *
 * <p>A singleton object that helps any UnderscoreFrontController implementor to 
 * execute a module call, as it holds the only ModuleStorage instance.</p>
 * 
 * @author JeyDotC
 */
class UnderscoreFrontControllerHelper {

    /**
     *
     * @var UnderscoreFrontControllerHelper 
     */
    private static $instance;

    /**
     * 
     *<p><strong>Note:</strong> Once this class gets instanced all the dependencies
     * are satisfied, so the ModulesContext is available and the ModuleStorage
     * is ready to use.</p>
     * 
     * @return UnderscoreFrontControllerHelper
     */
    public static function instance() {
        if(self::$instance == null){
            self::$instance = new UnderscoreFrontControllerHelper();
        }
        
        return self::$instance;
    }

    /**
     *
     * @var ModuleStorage 
     */
    private $moduleStorage;

    /**
     * Initializes an UnderscoreFrontControllerHelper instance.
     */
    private function __construct() {
        $this->moduleStorage = ModuleStorage::instance();
    }

    // Clone is forbidden
    public function __clone() {
        trigger_error('No clone is allowed.', E_USER_ERROR);
    }

    /**
     * Gets from the configuration manager the default module call.
     *  
     * @return ModuleCall The dafault module call.
     */
    public function getDefaultModuleCall() {
        $app = $this->getConfig()->get("DefaultApp");
        $module = $this->getConfig()->get("DefaultModule");
        $task = "index";

        return new ModuleCall($app, $module, $task);
    }

    /**
     * Retrieves from the configuration manager the module which shall manage any
     * unhandled exception.
     * 
     * @param UnderscoreException $ex
     * @return ModuleCall 
     */
    public function getErrorsModuleCall(UnderscoreException $ex) {
        $app = $this->getConfig()->get("ErrorsApp");
        $module = $this->getConfig()->get("ErrorsModule");
        $task = "index";

        return new ModuleCall($app, $module, $task, $ex);
    }

    /**
     * Gets the configuration object from ModulesContext.
     * @return AppConfig
     */
    private function getConfig() {
        return ModulesContext::instance()->getConfig();
    }

    /**
     * Makes a module call and returns the resulting html.
     * 
     * @param ModuleCall $call A call to a module.
     * @return string The resulting html.
     */
    public function invokeModule(ModuleCall $call) {

        try {
            $html = $this->moduleStorage->execute($call);
        } catch (UnderscoreException $ex) {
            $errorsCall = $this->getErrorsModuleCall($ex);
            $html = $this->moduleStorage->execute($errorsCall);
        }

        return $html;
    }
    
    /**
     * Tells if the given application exists.
     * 
     * @param string $appName The application name.
     * @return boolean true if the application exists, false otherwise.
     */
    public function applicationExists($appName) {
        return $this->moduleStorage->applicationExsists($appName);
    }

}

?>
